package com.yanqu.road.server.manager.cricketcourt;

import com.yanqu.road.entity.cricket.config.CricketCourtConfig;
import com.yanqu.road.entity.cricket.court.*;
import com.yanqu.road.entity.cricket.court.helper.CourtGroupNumHelper;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class CricketCourtTest {

    private static Object lock = new Object();

    /**
     * 蛐蛐竞技场表
     */
    private static Map<Integer, CricketCourtConfig> cricketCourtConfigMap = new ConcurrentHashMap<>();

    /**
     * 跨服分组区服列表
     */
    private static Map<Integer, CricketCourtLockGroup> cricketServerGroupMap = new HashMap<>();

    /**
     * 当前竞技场信息
     */
    private static Map<Integer, CricketCourtData> courtDataMap = new ConcurrentHashMap<>();

    /**
     * 分组id同一轮次递增且唯一，不区分赛场
     * 竞技场分组信息=> 赛场,分组,分组信息
     */
    private static Map<Integer,Map<Integer, Map<Integer, CricketCourtGroupData>>> courtGroupDataMap = new ConcurrentHashMap<>();

    /**
     * serverId,userId,竞技场玩家信息
     */
    private static Map<Long, Map<Long, CricketCourtUserData>> courtUserDataMap = new ConcurrentHashMap<>();

    /**
     * 榜单信息=> 轮次,赛场,分组,榜单
     */
    private static Map<Integer, Map<Integer, Map<Integer, CricketCourtRankListModel>>> rankListModelMap = new ConcurrentHashMap<>();

    /**
     * 匹配分组
     * 匹配分组id，匹配分组
     */
    private static Map<Integer, CricketCourtGroupMatchData> groupMatchDataMap = new ConcurrentHashMap<>();

    /**
     * 当前竞技场轮次
     */
    private static AtomicInteger curRound = new AtomicInteger(0);

    /**
     * 匹配分组id
     */
    private static AtomicInteger maxMatchGroupId = new AtomicInteger(0);

    /**
     * 用户数据
     */
    private static AtomicLong userId = new AtomicLong(0);
    private static AtomicLong serverId = new AtomicLong(0);
    private static AtomicInteger serverGroupId = new AtomicInteger(0);

    /**
     * 分组id
     */
    private static AtomicInteger maxGroupId = new AtomicInteger(0);


    private static RandomHelper randomHelper = new RandomHelper();

    /**
     * 榜单最大长度,暂不限制，在分组里都是上榜的，由分组名单控制
     */
    public static int getMaxRank() {
        return 99999;
    }

    public static void initData(int groupCnt, int serverCnt, int userNum) {
        while (cricketServerGroupMap.size() < groupCnt) {
            for (int i = 0; i < serverCnt; i++) {
                if (serverId.incrementAndGet() % serverCnt == 1) {
//                serverId.incrementAndGet();
                    CricketCourtLockGroup serverGroup = new CricketCourtLockGroup();
                    serverGroup.setGroupId(serverGroupId.incrementAndGet());
                    serverGroup.setRound(curRound.get());
                    serverGroup.setServerList(new HashSet<>());
                    serverGroup.setLockTime(System.currentTimeMillis());
                    cricketServerGroupMap.put(serverGroupId.get(), serverGroup);
                }
                cricketServerGroupMap.get(serverGroupId.get()).getServerList().add(serverId.get());
                // 每个服务器初始化100个用户
                for (int j = 0; j < userNum; j++) {
                    getCricketCourtUserData(serverId.get(), userId.incrementAndGet());
                }
            }
        }
    }


    public static void main(String[] args) {
        initCourtConfig();
        // 20个跨服分组，每个跨服分组10个服务器，每个服务器100个玩家
        initData(1, 1, 25521);
        // 分组模拟10轮数据
        while (curRound.get() < 10) {
            // 生成新轮次数据
            genNewRoundCourtData();
            // 分组信息
            courtGroupDataMap.put(curRound.get(), new ConcurrentHashMap<>());
            // 分组编号也重新计数
            maxGroupId = new AtomicInteger(0);
            // 晋级、淘汰
            for (Map<Long, CricketCourtUserData> dataMap : courtUserDataMap.values()) {
                for (CricketCourtUserData userData : dataMap.values()) {
                    changeRound(userData);
                }
            }
            // 分组
            generateGroup();
            // 用户加入分组
            for (Map<Long, CricketCourtUserData> dataMap : courtUserDataMap.values()) {
                for (CricketCourtUserData userData : dataMap.values()) {
                    scoreChange(userData.getServerId(), userData.getUserId(), randomHelper.next(0, 2000));
                }
            }
        }
        for (Map.Entry<Integer, Map<Integer, Map<Integer, CricketCourtGroupData>>> entry : courtGroupDataMap.entrySet()) {
            Integer round = entry.getKey();
            Map<Integer, Map<Integer, CricketCourtGroupData>> courtValue = entry.getValue();
            for (Map.Entry<Integer, Map<Integer, CricketCourtGroupData>> mapEntry : courtValue.entrySet()) {
                Integer courtId = mapEntry.getKey();
                Map<Integer, CricketCourtGroupData> groupValue = mapEntry.getValue();
                int groupId = 1;
                for (Map.Entry<Integer, CricketCourtGroupData> dataEntry : groupValue.entrySet()) {
                    CricketCourtGroupData groupData = dataEntry.getValue();
                    System.out.println("轮次id:" + round + ",赛场id:" + courtId + ",分组id:" + groupId++ + ",人数:" + groupData.getNum());
                }
            }
        }
    }

    /**
     * 分数变更调用这个方法
     */
    public static void scoreChange(long serverId, long userId, long score) {
        CricketCourtUserData userData = getCricketCourtUserData(serverId, userId);
        if (userData == null) {
            return;
        }
        if (!hasGroup(userData)) {
            // 还没分组的话新分数，正常来说不会出现, 做个容错
            // 加入新分组
            joinGroup(userData);
        }
        if (score == userData.getScore()) {
            return;
        }
        // 获取下分数变动前的数据
        userData.setScore(score);
        userData.setUpdateTime(System.currentTimeMillis());
        rankChange(userData);
    }

    /**
     * 用户是否有分组信息
     *
     * @param userData 用户数据
     */
    private static boolean hasGroup(CricketCourtUserData userData) {
        if (userData == null) {
            return false;
        }
        return userData.getGroupId() != -1;
    }

    /**
     * 获取竞技场用户数据，不存在则初始化一个
     */
    public static CricketCourtUserData getCricketCourtUserData(long serverId, long userId) {
        if (serverId <= 0 || userId <= 0) {
            return null;
        }
        if (!courtUserDataMap.containsKey(serverId)) {
            synchronized (courtUserDataMap) {
                if (!courtUserDataMap.containsKey(serverId)) {
                    courtUserDataMap.put(serverId, new ConcurrentHashMap<>());
                }
            }
        }
        Map<Long, CricketCourtUserData> map = courtUserDataMap.get(serverId);
        if (!map.containsKey(userId)) {
            synchronized (map) {
                if (!map.containsKey(userId)) {
                    CricketCourtUserData userData = new CricketCourtUserData();
                    userData.setServerId(serverId);
                    userData.setUserId(userId);
                    // 初始化赛场id
                    userData.setCourtId(1);
                    // -1 未分组状态
                    userData.setGroupId(-1);
                    // 初始化分数
                    userData.setScore(1000);
                    userData.setParam("");
                    userData.setLastCourtId(-1);
                    userData.setLastRank(-1);
                    userData.setRound(curRound.get());
                    userData.setUpdateTime(System.currentTimeMillis());
                    userData.setDefenseDataList(new ArrayList<>());
                    userData.setCourtBadgeId(0);
                    userData.setInsertOption();
                    map.put(userId, userData);
                }
            }
        }
        return map.get(userId);
    }


    /**
     * 轮次切换
     *
     * @param userData 用户数据
     */
    public static void changeRound(CricketCourtUserData userData) {
        if (userData.getRound() == curRound.get()) {
            return;
        }
        // 记录一下切换轮次前的数据
        userData.setLastCourtId(userData.getCourtId());
        // 上一轮的排名
        int myLastRank = -1;
        // 判断下我有没有在分组内,不在分组直接降级
        if (userData.getGroupId() == -1) {
            CricketCourtConfig preOpenCourtConfig = getPreOpenCourtConfig(userData.getCourtId());
            if (preOpenCourtConfig != null) {
                userData.setCourtId(preOpenCourtConfig.getCourtId());
            }
        } else {
            // 获取上一轮的赛场排名数据
            CricketCourtRankListModel rankListModel = getRankListModel(userData.getRound(), userData.getCourtId(), userData.getGroupId());
            // 分组人数
            int groupNum = rankListModel.getRankList().size();
            myLastRank = rankListModel.getRank(userData);
            // 晋级  rank => [1,upNum] 且有下一个赛场
            CricketCourtConfig nextOpenCourtConfig = getNextOpenCourtConfig(userData.getCourtId());
            // 当前场次晋级人数
            int upCnt = getUpCnt(userData.getCourtId(), groupNum);
            // 当前场次保留人数
            int keepCnt = getKeepCnt(userData.getCourtId(), groupNum);
            if (myLastRank >= 1 && myLastRank <= upCnt) {
                if (nextOpenCourtConfig != null) {
//                    System.out.println("用户排名:" + myLastRank + ",晋级从" + userData.getCourtId() + "晋到" + nextOpenCourtConfig.getCourtId());
                    userData.setCourtId(nextOpenCourtConfig.getCourtId());
                }
                // 保留人数，不需要处理
            } else if (keepCnt > 0 && myLastRank >= upCnt + 1 && myLastRank <= upCnt + keepCnt) {
                // 保留人数，不需要处理
//                System.out.println("用户排名:" + myLastRank + ",用户赛场不变");
            } else {
                // 剩下的全部淘汰
                CricketCourtConfig preOpenCourtConfig = getPreOpenCourtConfig(userData.getCourtId());
                if (preOpenCourtConfig != null) {
//                    System.out.println("用户排名:" + myLastRank + ",淘汰从"+userData.getCourtId()+"掉到"+preOpenCourtConfig.getCourtId());
                    userData.setCourtId(preOpenCourtConfig.getCourtId());
                }
                // 保留人数，不需要处理
            }
        }
        userData.setLastRank(myLastRank);
        userData.setGroupId(-1);
        userData.setScore(1000);
        userData.setParam("");
        userData.setRound(curRound.get());
        userData.setUpdateTime(System.currentTimeMillis());
    }

    public static CricketCourtConfig getCricketCourtConfigByType(int type) {
        for (CricketCourtConfig courtConfig : cricketCourtConfigMap.values()) {
            if (courtConfig.getCourtType() == type) {
                return courtConfig;
            }
        }
        return null;
    }



    /**
     * 获取下一个开放的赛场
     *
     * @param courtId 当前赛场id
     */
    public static CricketCourtConfig getNextOpenCourtConfig(int courtId) {
        CricketCourtConfig curConfig = getCricketCourtConfig(courtId);
        int courtType = curConfig.getCourtType();
        // 获取下一个赛场
        CricketCourtConfig nextConfig = getCricketCourtConfigByType(courtType + 1);
        if (nextConfig != null) {
            if (nextConfig.getCourtState() == 0) {
                // 再获取下一个
                return getNextOpenCourtConfig(nextConfig.getCourtId());
            } else {
                return nextConfig;
            }
        } else {
            return null;
        }
    }


    /**
     * 获取上一个开放的赛场
     *
     * @param courtId 当前赛场id
     */
    public static CricketCourtConfig getPreOpenCourtConfig(int courtId) {
        CricketCourtConfig curConfig = getCricketCourtConfig(courtId);
        int courtType = curConfig.getCourtType();
        // 获取前一个赛场
        CricketCourtConfig preConfig = getCricketCourtConfigByType(courtType - 1);
        if (preConfig != null) {
            if (preConfig.getCourtState() == 0) {
                // 再获取前一个
                return getPreOpenCourtConfig(preConfig.getCourtId());
            } else {
                return preConfig;
            }
        } else {
            return null;
        }
    }


    /**
     * 生成新一轮的竞技场信息
     */
    public static void genNewRoundCourtData() {
        CricketCourtData courtData = new CricketCourtData();
        // 超过了，重置轮次
        courtData.setRound(curRound.incrementAndGet());
        // 结算时间
        courtData.setRewardTime(DateHelper.getTodayZeroTimeStamp() + 4200 * DateHelper.MINUTE_MILLIONS);
        // 结束时间
        courtData.setEndTime(DateHelper.getTodayZeroTimeStamp() + 3 * DateHelper.DAY_MILLIONS);
        courtData.setGenerateGroup(false);
        courtData.setRankReward(false);
        courtData.setUpdateTime(System.currentTimeMillis());
        courtData.setInsertOption();
        courtDataMap.put(curRound.get(), courtData);
    }

    public static CricketCourtData getCricketCourtData(int round) {
        return courtDataMap.get(round);
    }


    /**
     * 生成分组
     */
    public static void generateGroup() {
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        // 判断下当前轮次是否已分组
        if (courtData == null || courtData.isGenerateGroup()) {
            return;
        }
        synchronized (lock) {
            if (courtData.isGenerateGroup()) {
                return;
            }
            maxMatchGroupId = new AtomicInteger(0);
            // 开始分组
            // 有哪些赛场
            Set<Integer> courtIdSet = new HashSet<>();
            // 默认有第一赛场
            courtIdSet.add(1);
            for (Map<Long, CricketCourtUserData> userDataMap : courtUserDataMap.values()) {
                for (CricketCourtUserData courtUserData : userDataMap.values()) {
                    courtIdSet.add(courtUserData.getCourtId());
                }
            }
            for (int courtId : courtIdSet) {
                // 生成赛场的分组匹配信息
                generateMatchGroup(courtId);
            }
            courtData.setGenerateGroup(true);
        }
    }

    /**
     * 匹配分组
     *
     * @param courtId 赛场id
     */
    private static void generateMatchGroup(int courtId) {
        // 学徒场是特殊处理的,直接读运营给的区服范围
        if (courtId == getInitCourtConfig().getCourtId()) {
            for (CricketCourtLockGroup lockGroup : cricketServerGroupMap.values()) {
                CricketCourtGroupMatchData groupMatchData = new CricketCourtGroupMatchData();
                groupMatchData.setRound(curRound.get());
                groupMatchData.setCourtId(courtId);
                // 学徒场只有一个分组范围,最小量级
                List<Integer> serverGroupIdList = new ArrayList<>();
                serverGroupIdList.add(lockGroup.getGroupId());
                groupMatchData.setServerGroupIdList(serverGroupIdList);
                // 更新赛场分组上限
                groupMatchData.setGroupLimit(getCourtGroupLimit(courtId, groupMatchData));
                groupMatchData.setMatchGroupId(maxMatchGroupId.incrementAndGet());
                // 开服天数
                long openDay = getAverageServerOpenDay(lockGroup);
                // 开服天数区间索引
                groupMatchData.setServerOpenDayIndex(getServerOpenDayRangeIndex(courtId, openDay));
                groupMatchData.setUpdateTime(System.currentTimeMillis());
                groupMatchData.setInsertOption();
                groupMatchDataMap.put(groupMatchData.getMatchGroupId(), groupMatchData);
                // 扩充分组时初始化分组，生成分组
                initCourtGroup(courtId, groupMatchData);
            }
        } else {
            // 其他的按规则分组
            // 初始生成下空分组
            initMatchGroup(courtId, cricketServerGroupMap.values());
            // 开始分配
            for (CricketCourtLockGroup lockGroup : cricketServerGroupMap.values()) {
                putMatchGroup(courtId, lockGroup);
            }
        }
    }


    /**
     * 初始空的匹配分组
     *
     * @param courtId             赛场id
     * @param cricketServerGroups 分组
     */
    private static void initMatchGroup(int courtId, Collection<CricketCourtLockGroup> cricketServerGroups) {
        CricketCourtConfig courtConfig = getCricketCourtConfig(courtId);
        Map<Integer, List<CricketCourtLockGroup>> openMap = new ConcurrentHashMap<>();
        for (CricketCourtLockGroup lockGroup : cricketServerGroups) {
            // 开服天数
            long openDay = getAverageServerOpenDay(lockGroup);
            // 开服天数区间索引
            int dayRangeIndex = getServerOpenDayRangeIndex(courtId, openDay);
            List<CricketCourtLockGroup> list = openMap.getOrDefault(dayRangeIndex, new ArrayList<>());
            list.add(lockGroup);
            openMap.put(dayRangeIndex, list);
        }
        // 分一下组
        Map<Integer, Integer> groupCntMap = new HashMap<>();
        for (Map.Entry<Integer, List<CricketCourtLockGroup>> entry : openMap.entrySet()) {
            Integer openDayIndex = entry.getKey();
            // 计算下多少个分组
            // 区服数量
            int serverCnt = 0;
            for (CricketCourtLockGroup lockGroup : entry.getValue()) {
                if (lockGroup == null) {
                    continue;
                }
                serverCnt += lockGroup.getServerList().size();
            }
            // 计算出有多少个匹配分组,做个容错，和分组取个最小值，防止大于匹配分组出现空分组
            groupCntMap.put(openDayIndex, (int) Math.min(entry.getValue().size(), Math.ceil(serverCnt * 1.0 / courtConfig.getFightRangeServer())));
        }

        // 初始化一下分组
        for (Map.Entry<Integer, Integer> entry : groupCntMap.entrySet()) {
            for (int i = 0; i < entry.getValue(); i++) {
                CricketCourtGroupMatchData groupMatchData = new CricketCourtGroupMatchData();
                groupMatchData.setRound(curRound.get());
                groupMatchData.setCourtId(courtId);
                // 这里空的就行
                groupMatchData.setServerGroupIdList(new ArrayList<>());
                // 更新赛场分组上限
                groupMatchData.setGroupLimit(getCourtGroupLimit(courtId, groupMatchData));
                groupMatchData.setMatchGroupId(maxMatchGroupId.incrementAndGet());
                // 开服天数区间索引
                groupMatchData.setServerOpenDayIndex(entry.getKey());
                groupMatchData.setUpdateTime(System.currentTimeMillis());
                groupMatchData.setInsertOption();
                groupMatchDataMap.put(groupMatchData.getMatchGroupId(), groupMatchData);
            }
        }

    }


    private static int getGroupCnt(int courtId, int matchGroupId) {
        if (!courtGroupDataMap.get(curRound.get()).containsKey(courtId)) {
            return 0;
        }
        int groupCnt = 0;
        for (CricketCourtGroupData groupData : courtGroupDataMap.get(curRound.get()).get(courtId).values()) {
            if (groupData.getMatchGroupId() != matchGroupId) {
                continue;
            }
            groupCnt++;
        }
        return groupCnt;
    }

    /**
     * 添加分组
     */
    public static CricketCourtGroupData addGroup(int courtId, int matchGroupId) {
        CricketCourtGroupData groupData = new CricketCourtGroupData();
        groupData.setCourtId(courtId);
        groupData.setGroupId(maxGroupId.incrementAndGet());
        groupData.setMatchGroupId(matchGroupId);
        groupData.setNum(0);
        groupData.setRound(curRound.get());
        groupData.setUpdateTime(System.currentTimeMillis());
        groupData.setInsertOption();
        int groupId = groupData.getGroupId();
        if (!courtGroupDataMap.get(curRound.get()).containsKey(courtId)) {
            courtGroupDataMap.get(curRound.get()).put(courtId, new ConcurrentHashMap<>());
        }
        if (!courtGroupDataMap.get(curRound.get()).get(courtId).containsKey(groupId)) {
            courtGroupDataMap.get(curRound.get()).get(courtId).put(groupId, groupData);
        }
        return groupData;
    }


    /**
     * 初始化分組
     */
    private static void initCourtGroup(int courtId, CricketCourtGroupMatchData groupMatchData) {
        // 计算需要添加多少个赛场分组
        int groupCnt = getGroupCnt(courtId, groupMatchData.getMatchGroupId());
        int groupLimit = groupMatchData.getGroupLimit();
        while (groupCnt < groupLimit) {
            addGroup(courtId, groupMatchData.getMatchGroupId());
            groupCnt++;
        }
    }

    /**
     * 加入匹配分组
     *
     * @param courtId 赛场id
     */
    private static CricketCourtGroupMatchData putMatchGroup(int courtId, CricketCourtLockGroup lockGroup) {
        CricketCourtConfig courtConfig = getCricketCourtConfig(courtId);
        // 开服天数
        long openDay = getAverageServerOpenDay(lockGroup);
        // 开服天数区间索引
        int dayRangeIndex = getServerOpenDayRangeIndex(courtId, openDay);

        // 目标分组区服数量
        int size = lockGroup.getServerList().size();

        long nowTime = System.currentTimeMillis();

        List<CricketCourtGroupMatchData> matchDataList = new ArrayList<>();
        // 找出没满的区服分组范围
        int minServerCnt = Integer.MAX_VALUE;
        for (CricketCourtGroupMatchData groupMatchData : groupMatchDataMap.values()) {
            // 开服天数区间相同的
            if (courtId != groupMatchData.getCourtId() || groupMatchData.getServerOpenDayIndex() != dayRangeIndex) {
                continue;
            }
            // 区服数量
            int serverCnt = 0;
            for (Integer groupId : groupMatchData.getServerGroupIdList()) {
                CricketCourtLockGroup serverGroup = getServerGroup(groupId);
                if (serverGroup == null) {
                    continue;
                }
                serverCnt += serverGroup.getServerList().size();
            }
            // 满足条件的，且
            if (serverCnt + size > courtConfig.getFightRangeServer()) {
                continue;
            }
            // 找下下最小的区服分组
            if (serverCnt <= minServerCnt) {
                if (serverCnt < minServerCnt) {
                    minServerCnt = serverCnt;
                    matchDataList = new ArrayList<>();
                }
                // 找下下最小的区服分组
                matchDataList.add(groupMatchData);
            }
        }
        // 随机一个分组出来
        CricketCourtGroupMatchData groupMatchData = null;
        if (matchDataList.size() > 0) {
            groupMatchData = matchDataList.get(randomHelper.next(0, matchDataList.size()));
            groupMatchData.getServerGroupIdList().add(lockGroup.getGroupId());
            // 更新赛场分组上限
            groupMatchData.setGroupLimit(getCourtGroupLimit(courtId, groupMatchData));
            groupMatchData.setUpdateTime(nowTime);
            groupMatchData.setUpdateOption();
        } else {
            // 新增一个匹配分组
            groupMatchData = new CricketCourtGroupMatchData();
            groupMatchData.setRound(curRound.get());
            groupMatchData.setCourtId(courtId);
            // 学徒场只有一个分组范围,最小量级
            List<Integer> serverGroupIdList = new ArrayList<>();
            serverGroupIdList.add(lockGroup.getGroupId());
            groupMatchData.setServerGroupIdList(serverGroupIdList);
            groupMatchData.setMatchGroupId(maxMatchGroupId.incrementAndGet());
            // 更新赛场分组上限
            groupMatchData.setGroupLimit(getCourtGroupLimit(courtId, groupMatchData));
            groupMatchData.setServerOpenDayIndex(dayRangeIndex);
            groupMatchData.setUpdateTime(nowTime);
            groupMatchData.setInsertOption();
            groupMatchDataMap.put(groupMatchData.getMatchGroupId(), groupMatchData);
        }
        // 扩充分组时初始化分组，生成分组
        initCourtGroup(courtId, groupMatchData);
        return groupMatchData;
    }



    /**
     * 获取分组内的平均开服天数
     */
    public static long getAverageServerOpenDay(CricketCourtLockGroup lockGroup) {
        return 100;
    }

    /**
     * 获取开服天数区间索引
     */
    public static int getServerOpenDayRangeIndex(int courtId, long openDay) {
        return 0;
    }


    /**
     * 加入分组
     */
    public static void joinGroup(CricketCourtUserData courtUserData) {
        int courtId = courtUserData.getCourtId();
        // 没有赛场
        if (courtId == -1) {
            return;
        }
        if (courtUserData.getGroupId() != -1) {
            // 有分组不处理
            return;
        }
        CricketCourtGroupData groupData = null;
        synchronized (lock) {
            // 获取下匹配分组
            CricketCourtGroupMatchData groupMatchData = getMatchGroupId(courtId, courtUserData.getServerId());
            if (groupMatchData == null) {
                // 需要添加个分组
                CricketCourtLockGroup lockGroup = CrossCricketCourtMgr.getLockGroupByServerId(courtUserData.getServerId());
                if (lockGroup != null) {
                    // 加一个新的匹配分组
                    groupMatchData = putMatchGroup(courtId, lockGroup);
                }
            }
            groupData = getGroupData(courtId, getRandomGroupId(courtUserData, false));
            // 第一次取不到说明没有空的分组，都是塞满了，第二次取无视分组人数上限
            if (groupData == null) {
                if (courtId == getInitCourtConfig().getCourtId()) {
                    // 学徒场满人则加分组
                    if (groupMatchData != null) {
                        groupData = addGroup(courtId, groupMatchData.getMatchGroupId());
                    }
                } else {
                    groupData = getGroupData(courtId, getRandomGroupId(courtUserData, true));
                }
            }
            if (groupData == null) {
                // 还是取不到就别进了，有异常了
                return;
            }
            groupData.setNum(groupData.getNum() + 1);
            groupData.setUpdateTime(System.currentTimeMillis());
        }
        courtUserData.setGroupId(groupData.getGroupId());
        courtUserData.setScore(1000);
        courtUserData.setUpdateTime(System.currentTimeMillis());
        // 更新下分组榜单
        rankChange(courtUserData);
    }

    /**
     * 获取初始的赛场(最小开放)
     */
    public static CricketCourtConfig getInitCourtConfig() {
        int minType = Integer.MAX_VALUE;
        int courtId = -1;
        for (CricketCourtConfig courtConfig : cricketCourtConfigMap.values()) {
            if (courtConfig.getCourtState() == 0) {
                continue;
            }
            if (courtConfig.getCourtType() < minType) {
                minType = courtConfig.getCourtType();
                courtId = courtConfig.getCourtId();
            }
        }
        return getCricketCourtConfig(courtId);
    }


    /**
     * 获取随机一个分组
     *
     * @param ignoreLimit 是否忽略上限
     */
    public static int getRandomGroupId(CricketCourtUserData courtUserData, boolean ignoreLimit) {
        int courtId = courtUserData.getCourtId();
        if (!courtGroupDataMap.get(curRound.get()).containsKey(courtId)) {
            return -1;
        }
        // 获取我的匹配分组
        CricketCourtGroupMatchData groupMatchData = getMatchGroupId(courtId, courtUserData.getServerId());
        if (groupMatchData == null) {
            return -1;
        }
        List<Integer> groupIdList = new ArrayList<>();
        Map<Integer, CricketCourtGroupData> dataMap = courtGroupDataMap.get(curRound.get()).getOrDefault(courtId, new ConcurrentHashMap<>());
        int minNum = Integer.MAX_VALUE;
        if (ignoreLimit) {
            // 无视分组人数上限， 往人数最少的分组塞人
            for (CricketCourtGroupData groupData : dataMap.values()) {
                if (groupData.getMatchGroupId() != groupMatchData.getMatchGroupId()) {
                    continue;
                }
                if (groupData.getNum() <= minNum) {
                    if (groupData.getNum() < minNum) {
                        minNum = groupData.getNum();
                        // 清空下列表
                        groupIdList = new ArrayList<>();
                    }
                    groupIdList.add(groupData.getGroupId());
                }
            }
        } else {
            List<CourtGroupNumHelper> groupNumHelpers = new ArrayList<>();
            for (CricketCourtGroupData groupData : dataMap.values()) {
                if (groupData.getMatchGroupId() != groupMatchData.getMatchGroupId()) {
                    continue;
                }
                groupNumHelpers.add(new CourtGroupNumHelper(groupData.getGroupId(), groupData.getNum()));
            }
            // 排个序,人数从大到小排序
            groupNumHelpers.sort(Comparator.comparing(CourtGroupNumHelper::getNum).reversed());
            int cricketFightExpansionGroup = 1;
            int totalRangeSize = groupNumHelpers.size() % cricketFightExpansionGroup == 0 ? groupNumHelpers.size() / cricketFightExpansionGroup : groupNumHelpers.size() / cricketFightExpansionGroup + 1;
            CricketCourtConfig courtConfig = getCricketCourtConfig(courtId);
            for (int i = 0; i < totalRangeSize; i++) {
                if (groupIdList.size() > 0) {
                    // 找到了退出
                    break;
                }
                // 第i个区间  [i * GameConfig.CRICKET_FIGHT_EXPANSION_GROUP , (i+1) * GameConfig.CRICKET_FIGHT_EXPANSION_GROUP)
                for (int j = i * cricketFightExpansionGroup; j < (i + 1) * cricketFightExpansionGroup; j++) {
                    int index = Math.min(j, groupNumHelpers.size() - 1);
                    CourtGroupNumHelper helper = groupNumHelpers.get(index);
                    if (helper.getNum() >= courtConfig.getNum()) {
                        continue;
                    }
                    if (helper.getNum() <= minNum) {
                        if (helper.getNum() < minNum) {
                            minNum = helper.getNum();
                            // 清空下列表
                            groupIdList = new ArrayList<>();
                        }
                        groupIdList.add(helper.getGroupId());
                    }
                }
            }
        }
        if (groupIdList.size() == 0) {
            return -1;
        }
        return groupIdList.get(randomHelper.next(0, groupIdList.size()));
    }



    /**
     * 获取分组信息
     */
    public static CricketCourtGroupData getGroupData(int courtId, int groupId) {
        if (!courtGroupDataMap.get(curRound.get()).containsKey(courtId)) {
            return null;
        }
        return courtGroupDataMap.get(curRound.get()).get(courtId).get(groupId);

    }



    /**
     * 分组榜单变更
     */
    public static void rankChange(CricketCourtUserData userData) {
        if (curRound.get() == 0 || userData == null) {
            return;
        }
        CricketCourtRankListModel rankListModel = getRankListModel(curRound.get(), userData.getCourtId(), userData.getGroupId());
        rankListModel.rankChange(userData);
    }

    public static CricketCourtRankListModel getRankListModel(int round, int courtId, int groupId) {
        if (!rankListModelMap.containsKey(round)) {
            rankListModelMap.put(round, new ConcurrentHashMap<>());
        }
        if (!rankListModelMap.get(round).containsKey(courtId)) {
            rankListModelMap.get(round).put(courtId, new ConcurrentHashMap<>());
        }
        if (!rankListModelMap.get(round).get(courtId).containsKey(groupId)) {
            CricketCourtRankListModel model = new CricketCourtRankListModel(groupId, getMaxRank(), new CricketCourtRankListSort());
            List<CricketCourtUserData> rankList = new ArrayList<>();
            for (Map<Long, CricketCourtUserData> userMap : courtUserDataMap.values()) {
                for (CricketCourtUserData data : userMap.values()) {
                    if (data.getRound() == round && data.getCourtId() == courtId && data.getGroupId() == groupId) {
                        rankList.add(data);
                    }
                }
            }
            model.setRankList(rankList);
            rankListModelMap.get(round).get(courtId).put(groupId, model);
        }
        return rankListModelMap.get(round).get(courtId).get(groupId);
    }



    /**
     * 获取当前区服的匹配分组
     */
    public static CricketCourtGroupMatchData getMatchGroupId(int courtId, long serverId) {
        for (CricketCourtGroupMatchData matchData : groupMatchDataMap.values()) {
            if (matchData.getCourtId() != courtId) {
                continue;
            }
            for (Integer groupId : matchData.getServerGroupIdList()) {
                CricketCourtLockGroup serverGroup = getServerGroup(groupId);
                if (serverGroup == null) {
                    continue;
                }
                if (serverGroup.getServerList().contains(serverId)) {
                    return matchData;
                }
            }
        }
        return null;
    }


    /**
     * 更新赛场分组上限
     */
    public static int getCourtGroupLimit(int courtId, CricketCourtGroupMatchData groupMatchData) {
        // 低级场特殊处理
        if (courtId == getInitCourtConfig().getCourtId()) {
            return 1;
        }
        List<Long> allServerIdList = new ArrayList<>();
        for (Integer groupId : groupMatchData.getServerGroupIdList()) {
            CricketCourtLockGroup serverGroup = getServerGroup(groupId);
            if (serverGroup != null) {
                allServerIdList.addAll(serverGroup.getServerList());
            }
        }
        // 获取当前赛场的人数
        int userCnt = 0;
        for (Map<Long, CricketCourtUserData> userDataMap : courtUserDataMap.values()) {
            for (CricketCourtUserData userData : userDataMap.values()) {
                if (userData.getCourtId() == courtId && allServerIdList.contains(userData.getServerId())) {
                    userCnt++;
                }
            }
        }
        CricketCourtConfig courtConfig = getCricketCourtConfig(courtId);
        int groupLimit = userCnt / courtConfig.getNum();
        if (userCnt % courtConfig.getNum() >= courtConfig.getModLimit()) {
            groupLimit = groupLimit + 1;
        }
        // 做个容错,有人至少有一组
        if (userCnt > 0) {
            groupLimit = Math.max(1, groupLimit);
        }
        return courtConfig.getGroupLimit() == -1 ? groupLimit : Math.min(groupLimit, courtConfig.getGroupLimit());

    }

    public static CricketCourtLockGroup getServerGroup(int groupId) {
        return cricketServerGroupMap.get(groupId);
    }

    public static CricketCourtConfig getCricketCourtConfig(int courtId) {
        return cricketCourtConfigMap.get(courtId);
    }

    private static void initCourtConfig() {
        CricketCourtConfig courtConfig1 = new CricketCourtConfig();
        courtConfig1.setCourtId(1);
        courtConfig1.setCourtName("学徒场");
        courtConfig1.setCourtType(1);
        courtConfig1.setFightRangeServer(99999);
        courtConfig1.setFightRangeDay("0");
        courtConfig1.setNum(500);
        courtConfig1.setGroupLimit(-1);
        courtConfig1.setUpNum(300);
        courtConfig1.setKeepNum(700);
        courtConfig1.setCourtState(1);
        courtConfig1.setModLimit(100);
        cricketCourtConfigMap.put(courtConfig1.getCourtId(), courtConfig1);

        CricketCourtConfig courtConfig2 = new CricketCourtConfig();
        courtConfig2.setCourtId(2);
        courtConfig2.setCourtName("学士场");
        courtConfig2.setCourtType(2);
        courtConfig2.setFightRangeServer(99999);
        courtConfig2.setFightRangeDay("0");
        courtConfig2.setNum(500);
        courtConfig2.setGroupLimit(-1);
        courtConfig2.setUpNum(200);
        courtConfig2.setKeepNum(300);
        courtConfig2.setCourtState(1);
        courtConfig2.setModLimit(300);
        cricketCourtConfigMap.put(courtConfig2.getCourtId(), courtConfig2);

        CricketCourtConfig courtConfig3 = new CricketCourtConfig();
        courtConfig3.setCourtId(3);
        courtConfig3.setCourtName("学者场");
        courtConfig3.setCourtType(3);
        courtConfig3.setFightRangeServer(99999);
        courtConfig3.setFightRangeDay("0");
        courtConfig3.setNum(500);
        courtConfig3.setGroupLimit(-1);
        courtConfig3.setUpNum(200);
        courtConfig3.setKeepNum(300);
        courtConfig3.setCourtState(1);
        courtConfig3.setModLimit(300);
        cricketCourtConfigMap.put(courtConfig3.getCourtId(), courtConfig3);

        CricketCourtConfig courtConfig4 = new CricketCourtConfig();
        courtConfig4.setCourtId(4);
        courtConfig4.setCourtName("良师场");
        courtConfig4.setCourtType(4);
        courtConfig4.setFightRangeServer(99999);
        courtConfig4.setFightRangeDay("0");
        courtConfig4.setNum(500);
        courtConfig4.setGroupLimit(-1);
        courtConfig4.setUpNum(200);
        courtConfig4.setKeepNum(200);
        courtConfig4.setCourtState(1);
        courtConfig4.setModLimit(300);
        cricketCourtConfigMap.put(courtConfig4.getCourtId(), courtConfig4);

        CricketCourtConfig courtConfig5 = new CricketCourtConfig();
        courtConfig5.setCourtId(5);
        courtConfig5.setCourtName("名师场");
        courtConfig5.setCourtType(5);
        courtConfig5.setFightRangeServer(99999);
        courtConfig5.setFightRangeDay("0");
        courtConfig5.setNum(500);
        courtConfig5.setGroupLimit(-1);
        courtConfig5.setUpNum(150);
        courtConfig5.setKeepNum(150);
        courtConfig5.setCourtState(1);
        courtConfig5.setModLimit(300);
        cricketCourtConfigMap.put(courtConfig5.getCourtId(), courtConfig5);

        CricketCourtConfig courtConfig6 = new CricketCourtConfig();
        courtConfig6.setCourtId(6);
        courtConfig6.setCourtName("大师场");
        courtConfig6.setCourtType(6);
        courtConfig6.setFightRangeServer(99999);
        courtConfig6.setFightRangeDay("0");
        courtConfig6.setNum(500);
        courtConfig6.setGroupLimit(-1);
        courtConfig6.setUpNum(100);
        courtConfig6.setKeepNum(100);
        courtConfig6.setCourtState(1);
        courtConfig6.setModLimit(300);
        cricketCourtConfigMap.put(courtConfig6.getCourtId(), courtConfig6);

        CricketCourtConfig courtConfig7 = new CricketCourtConfig();
        courtConfig7.setCourtId(7);
        courtConfig7.setCourtName("宗师场");
        courtConfig7.setCourtType(7);
        courtConfig7.setFightRangeServer(99999);
        courtConfig7.setFightRangeDay("0");
        courtConfig7.setNum(500);
        courtConfig7.setGroupLimit(1);
        courtConfig7.setUpNum(0);
        courtConfig7.setKeepNum(200);
        courtConfig7.setCourtState(1);
        courtConfig7.setModLimit(300);
        cricketCourtConfigMap.put(courtConfig7.getCourtId(), courtConfig7);

    }

    /**
     * 获取晋级人数
     * 向上取整
     * @param courtId  赛场id
     * @param groupNum 分组人数
     */
    public static int getUpCnt(int courtId, int groupNum) {
        CricketCourtConfig courtConfig = getCricketCourtConfig(courtId);
        if (courtConfig == null) {
            return 0;
        }
        if (groupNum == 0) {
            return 0;
        }
        // 获取晋级千分比
        int upNumRadio = courtConfig.getUpNum();
        // 计算晋级人数
        int upNum = BigDecimal.valueOf(groupNum).multiply(BigDecimal.valueOf(upNumRadio)).divide(BigDecimal.valueOf(1000), 0, RoundingMode.UP).intValue();
        return Math.max(0, Math.min(upNum, groupNum));
    }

    /**
     * 获取保留人数
     * 向上取整
     * @param courtId  赛场id
     * @param groupNum 分组人数
     */
    public static int getKeepCnt(int courtId, int groupNum) {
        CricketCourtConfig courtConfig = getCricketCourtConfig(courtId);
        if (courtConfig == null) {
            return 0;
        }
        if (groupNum == 0) {
            return 0;
        }
        // 获取保留千分比
        int keepNumRadio = courtConfig.getKeepNum();
        // 计算保留人数
        int keepNum = BigDecimal.valueOf(groupNum).multiply(BigDecimal.valueOf(keepNumRadio)).divide(BigDecimal.valueOf(1000), 0, RoundingMode.UP).intValue();
        return Math.max(0, Math.min(keepNum, groupNum));
    }

}
